package online.longzipeng.mywebdemo;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import online.longzipeng.mywebdemo.entity.User;
import online.longzipeng.mywebdemo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Author: lzp
 * @description:
 * @Date: 2023/3/3
 */
@Slf4j
@SpringBootTest(classes = MyWebDemoApplication.class,
		// 配置端口启动，否则获取失败
		webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class BatchDemo2 {

	@Autowired
	private UserMapper userMapper;

	/**
	 * 分页处理，已知总数
	 */
	@Test
	public void test1() {
		// 预定义分页参数
		int pageSize = 1000;
		int page = 0;

		// 计算总页数
		int total = userMapper.selectCount(null);
		int pages = total / pageSize;
		if (total % pageSize > 0) {
			pages++;
		}

		for (; page < pages; page++) {
			// 查询出需要处理的数据
			List<User> users = userMapper.selectList(Wrappers.<User>lambdaQuery()
					.last(String.format("LIMIT %d,%d", page * pageSize, pageSize)));

			for (User user : users) {

				/// 某些业务逻辑

			}
			/// 批量修改的操作

			if (CollUtil.isNotEmpty(users)) {
				User lastUser = users.get(users.size() - 1);
				log.info("最后一个要处理的用户的ID为：{}，名字：{}", lastUser.getId(), lastUser.getNickName());
			}
		}
	}

	/**
	 * 分页处理，未知总数
	 */
	@Test
	public void test2() {
		// 预定义分页参数
		int pageSize = 1000;
		int page = 0;
		for (; ; ) {
			// 查询出需要处理的数据
			List<User> users = userMapper.selectList(Wrappers.<User>lambdaQuery()
					.last(String.format("LIMIT %d,%d", (page++) * pageSize, pageSize)));
			for (User user : users) {

				/// 某些业务逻辑

			}
			/// 批量修改的操作

			if (CollUtil.isNotEmpty(users)) {
				User lastUser = users.get(users.size() - 1);
				log.info("最后一个要处理的用户的ID为：{}，名字：{}", lastUser.getId(), lastUser.getNickName());
			}

			if (users.size() < pageSize) {
				break;
			}
		}
	}

	/**
	 * 补充亿点点日志细节
	 */
	@Test
	public void test3() throws InterruptedException {
		// 预定义分页参数
		int pageSize = 1000;
		int page = 0;

		long start = System.currentTimeMillis();
		// 计算总页数
		int total = userMapper.selectCount(null);
		int pages = total / pageSize;
		if (total % pageSize > 0) {
			pages++;
		}
		// 处理失败的数据id集合
		List<Integer> wrongIds = new ArrayList<>();
		int handleCount = 0; // 总处理数
		int successCount = 0; // 处理成功数
		int minuteCount = 0; // 已经过的分钟数

		log.info("============= 开始处理数据 总条数{}，总页数{}，每页{}条 =============", total, pages, pageSize);
		for (; page < pages; page++) {
			log.info("============= 进度 {}/{} =============", page + 1, pages);
			// 查询出需要处理的数据
			List<User> users = userMapper.selectList(Wrappers.<User>lambdaQuery()
					.last(String.format("LIMIT %d,%d", page * pageSize, pageSize)));

			for (User user : users) {
				handleCount++;
				Thread.sleep(1);
				/// 某些业务逻辑
				if (user.getId() % 99 == 0) {
					wrongIds.add(user.getId());
				} else {
					successCount++;
				}

				/// 每隔10秒钟输出一次日志
				if ((System.currentTimeMillis() - start) / 1000 / 10 > minuteCount) {
					log.info("已耗时{} S", (System.currentTimeMillis() - start) / 1000);
					log.info("已处理 {} 条", handleCount);
					log.info("处理成功 {} 条", successCount);
					log.info("处理失败 {} 条", wrongIds.size());
					minuteCount++;
				}

			}
			/// 批量修改的操作

			if (CollUtil.isNotEmpty(users)) {
				User lastUser = users.get(users.size() - 1);
				log.info("已耗时{} S", (System.currentTimeMillis() - start) / 1000);
				log.info("已处理 {} 条", handleCount);
				log.info("处理成功 {} 条", successCount);
				log.info("处理失败 {} 条", wrongIds.size());
				log.info("最后一个要处理的用户的ID为：{}，名字：{}", lastUser.getId(), lastUser.getNickName());
			}
		}
		log.info("============= 处理完成 =============");
		log.info("总耗时{} S", (System.currentTimeMillis() - start) / 1000);
		log.info("已处理 {} 条", handleCount);
		log.info("处理成功 {} 条", successCount);
		log.info("处理失败 {} 条", wrongIds.size());
		log.info("处理失败 {}", wrongIds);

	}


	/**
	 * 多线程，按数据分割，均分给每个线程直接处理
	 */
	@Test
	public void test4() {
		// 预定义分页参数
		int threadNum = 5;

		long start = System.currentTimeMillis();

		// 计算总页数
		int total = userMapper.selectCount(null);
		// 线程总数的基数
		int threadTotalStep = total / threadNum;
		int more = total % threadNum;
		// 创建线程池，实际使用推荐用自定义线程池
		ExecutorService executorService = Executors.newFixedThreadPool(threadNum);

		CountDownLatch countDownLatch = new CountDownLatch(threadNum);

		for (int i = 0; i < threadNum; i++) {
			// 计算当前线程的总数
			int threadTotal = threadTotalStep;
			if (more > 0 && i == threadNum - 1) {
				threadTotal += more;
			}
			int finalI = i;
			int finalThreadTotal = threadTotal;
			// 执行业务
			executorService.execute(() -> {
				// 查询出需要处理的数据
				List<User> users = userMapper.selectList(Wrappers.<User>lambdaQuery()
						.last(String.format("LIMIT %d,%d", threadTotalStep * finalI, finalThreadTotal)));

				for (User user : users) {
					try {
						Thread.sleep(1);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					/// 某些业务逻辑

				}
				/// 批量修改的操作

				if (CollUtil.isNotEmpty(users)) {
					User lastUser = users.get(users.size() - 1);
					log.info("最后一个要处理的用户的ID为：{}，名字：{}", lastUser.getId(), lastUser.getNickName());
				}
				countDownLatch.countDown();
			});
		}

		try {
			countDownLatch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		log.info("总耗时{} S", (System.currentTimeMillis() - start) / 1000);
	}

}
